<template>
  <div class="editor-container">
    <div class="code-panel">
      <!-- 页签导航栏 -->
      <div class="file-tabs">
        <div
          v-for="(file, index) in files"
          :key="file.name"
          class="file-tab"
          :class="{ active: currentFileIndex === index }"
          @click="switchFile(index)"
        >
          <span class="file-icon" :class="getFileIconClass(file.name)">
            {{ getFileIconText(getFileIconClass(file.name)) }}
          </span>
          <span class="file-name">{{ file.name }}</span>
          <span
            v-if="files.length > 1"
            class="close-tab"
            @click.stop="closeFile(index)"
            >×</span
          >
        </div>
        <div class="add-file-tab" @click="showNewFileModal = true">+</div>
      </div>

      <!-- 新建文件弹窗 -->
      <div v-if="showNewFileModal" class="new-file-modal">
        <div class="modal-content">
          <h3>新建文件</h3>
          <input
            v-model="newFileName"
            placeholder="文件名 (例如: App.vue)"
            @keyup.enter="createNewFile"
          />
          <div class="modal-buttons">
            <button @click="createNewFile">创建</button>
            <button @click="showNewFileModal = false">取消</button>
          </div>
        </div>
      </div>

      <div class="dependency-hint" v-if="isPackageJsonFile">
        <div class="hint-message">
          <span>修改此文件中的dependencies对象来添加或删除第三方库</span>
          <button @click="refreshPreview" class="refresh-btn">
            应用依赖更改
          </button>
        </div>
        <div class="hint-tips">
          <p>提示：</p>
          <ul>
            <li>JSON不支持注释，系统会自动移除注释再解析</li>
            <li>键名必须使用双引号 "name": "value"</li>
            <li>最后一个属性后不能有逗号</li>
            <li>修改后点击"应用依赖更改"按钮更新预览</li>
          </ul>
        </div>
      </div>

      <codemirror
        v-model="code"
        placeholder="代码编辑区..."
        :style="{
          height: isPackageJsonFile
            ? 'calc(100% - 120px)'
            : 'calc(100% - 40px)',
        }"
        :autofocus="true"
        :indent-with-tab="true"
        :tab-size="2"
        :extensions="extensions"
        @ready="handleReady"
        @change="handleChange"
        @focus="log('focus', $event)"
        @blur="handleBlur"
      />
    </div>
    <div class="preview-container">
      <div class="preview-header">
        <span>预览区</span>
        <button @click="refreshPreview" class="refresh-btn">刷新预览</button>
      </div>
      <div class="preview-content">
        <div v-if="loading" class="loading-overlay">
          <div class="loading-spinner"></div>
          <div>加载中...</div>
        </div>
        <div v-if="error" class="error">{{ error }}</div>
        <div v-if="!loading && !error" class="component-container">
          <component :is="previewComp"></component>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import {
  defineAsyncComponent,
  ref,
  shallowRef,
  onMounted,
  markRaw,
  computed,
  watch,
} from "vue";
import * as Vue from "vue";
import { Codemirror } from "vue-codemirror";
import { vue } from "@codemirror/lang-vue";
import { javascript } from "@codemirror/lang-javascript";
import { json } from "@codemirror/lang-json";
import { html } from "@codemirror/lang-html";
import { oneDark } from "@codemirror/theme-one-dark";
import { loadModule } from "vue3-sfc-loader";
import * as Three from "three";

// 从模板文件导入初始文件内容
import {
  indexHtmlContent,
  mainTsContent,
  appVueContent,
  elementPlusDemoContent,
  packageJsonContent,
  fallbackCode,
  generateDefaultContent,
} from "../templates/index.js";

// 文件管理
const files = ref([
  { name: "index.html", content: indexHtmlContent },
  { name: "main.ts", content: mainTsContent },
  { name: "App.vue", content: appVueContent },
  { name: "ElementPlusDemo.vue", content: elementPlusDemoContent },
  { name: "package.json", content: packageJsonContent },
]);
const currentFileIndex = ref(2); // 默认打开App.vue

// 检查当前文件是否为package.json
const isPackageJsonFile = computed(() => {
  return files.value[currentFileIndex.value]?.name === "package.json";
});

// 新建文件相关
const showNewFileModal = ref(false);
const newFileName = ref("");

// 创建新文件
const createNewFile = () => {
  const fileName = newFileName.value.trim();
  if (!fileName) return;

  // 防止重名
  if (files.value.some((f) => f.name === fileName)) {
    alert(`文件 ${fileName} 已存在`);
    return;
  }

  // 使用模板工具函数生成默认内容
  const content = generateDefaultContent(fileName);

  files.value.push({ name: fileName, content });
  currentFileIndex.value = files.value.length - 1;
  showNewFileModal.value = false;
  newFileName.value = "";
};

// 切换文件
const switchFile = (index) => {
  currentFileIndex.value = index;
  code.value = files.value[index].content;
};

// 关闭文件
const closeFile = (index) => {
  if (files.value.length <= 1) return; // 至少保留一个文件

  files.value.splice(index, 1);
  if (currentFileIndex.value >= files.value.length) {
    currentFileIndex.value = files.value.length - 1;
  } else if (currentFileIndex.value === index) {
    // 当前文件被关闭，切换到前一个文件
    currentFileIndex.value = Math.max(0, index - 1);
  }
  code.value = files.value[currentFileIndex.value].content;
};

// 根据文件名获取文件图标类
const getFileIconClass = (fileName) => {
  if (fileName.endsWith(".vue")) return "icon-vue";
  if (fileName.endsWith(".js")) return "icon-js";
  if (fileName.endsWith(".ts")) return "icon-ts";
  if (fileName.endsWith(".json")) return "icon-json";
  if (fileName.endsWith(".html")) return "icon-html";
  if (fileName.endsWith(".css")) return "icon-css";
  return "icon-file";
};

// 根据文件图标类获取显示的图标文本
const getFileIconText = (iconClass) => {
  switch (iconClass) {
    case "icon-vue":
      return "Vue";
    case "icon-js":
      return "JS";
    case "icon-ts":
      return "TS";
    case "icon-json":
      return "JSON";
    case "icon-html":
      return "HTML";
    case "icon-css":
      return "CSS";
    default:
      return "File";
  }
};

// 默认组件代码
const defaultCode = appVueContent;

const code = ref(defaultCode || fallbackCode);
const previewComp = shallowRef(null);
const loading = ref(true); // 初始状态为加载中
const error = ref("");

// 根据文件类型选择不同的CodeMirror扩展
const extensions = computed(() => {
  const currentFile = files.value[currentFileIndex.value]?.name || "";
  const baseExtensions = [oneDark];

  if (currentFile.endsWith(".vue")) {
    return [...baseExtensions, vue()];
  } else if (currentFile.endsWith(".js")) {
    return [...baseExtensions, javascript()];
  } else if (currentFile.endsWith(".ts")) {
    return [...baseExtensions, javascript({ typescript: true })];
  } else if (currentFile.endsWith(".json")) {
    return [...baseExtensions, json()];
  } else if (currentFile.endsWith(".html")) {
    return [...baseExtensions, html()];
  }

  return baseExtensions;
});

const view = shallowRef();

// 缓存Map
const compiledCache = new Map();

// 准备就绪
const handleReady = (payload) => {
  view.value = payload.view;
  // 设置初始内容为当前选中文件内容
  code.value = files.value[currentFileIndex.value].content;
  // 初始化时编译组件
  compileComponent();
};

// 日志
const log = (type, event) => {
  console.log(type, event);
};

// 失去焦点时编译组件
const handleBlur = () => {
  // 保存内容到当前文件
  files.value[currentFileIndex.value].content = code.value;
  compileComponent();
};

// 处理输入变化
const handleChange = (val) => {
  // 保存当前文件的更改
  files.value[currentFileIndex.value].content = val;
};

// 刷新预览
const refreshPreview = () => {
  console.log("手动刷新预览");
  compileComponent();
};

// 编译组件函数
const compileComponent = async () => {
  console.log("开始编译组件...");
  loading.value = true;
  error.value = "";

  try {
    // 查找主Vue组件文件（默认为App.vue）
    const mainComponent = files.value.find((f) => f.name === "App.vue");
    if (!mainComponent) {
      error.value = "找不到主组件 App.vue";
      loading.value = false;
      return;
    }

    // 检查编辑器内容是否为空
    if (!mainComponent.content.trim()) {
      error.value = "主组件内容为空";
      loading.value = false;
      return;
    }

    // 检查是否包含基本Vue组件结构
    if (!mainComponent.content.includes("<template>")) {
      error.value = "主组件缺少<template>标签";
      loading.value = false;
      return;
    }

    // 清除之前的组件
    previewComp.value = null;

    // 创建一个虚拟文件系统，包括所有编辑器中的文件
    const virtualFileSystem = {};
    files.value.forEach((file) => {
      virtualFileSystem[`/${file.name}`] = file.content;
    });

    // 使用固定模块ID
    const moduleId = "/App.vue";

    // 清除缓存
    compiledCache.clear();

    // 创建一个库管理器，初始包含基础库
    const moduleCache = {
      vue: Vue,
      three: Three,

      // 添加对样式预处理器的预设支持
      scss: {
        render: (content) => content,
        renderSync: (options) => ({
          css: options.data || "",
          map: null,
          stats: {},
        }),
        process: (content) => ({ css: content }),
        processAsync: async (content) => ({ css: content }),
      },
      sass: {
        render: (content) => content,
        renderSync: (options) => ({
          css: options.data || "",
          map: null,
          stats: {},
        }),
        process: (content) => ({ css: content }),
        processAsync: async (content) => ({ css: content }),
      },
      less: {
        render: (content) => content,
        renderSync: (options) => ({
          css: options.data || "",
          map: null,
          stats: {},
        }),
        process: (content) => ({ css: content }),
        processAsync: async (content) => ({ css: content }),
      },
      stylus: {
        render: (content) => content,
        renderSync: (options) => ({
          css: options.data || "",
          map: null,
          stats: {},
        }),
        process: (content) => ({ css: content }),
        processAsync: async (content) => ({ css: content }),
      },
    };

    // 解析package.json中的依赖并从CDN加载
    const dependencies = {};
    let dependenciesLoadFailed = false;
    try {
      const packageFile = files.value.find((f) => f.name === "package.json");
      if (packageFile) {
        // 更健壮的JSON注释清理函数
        const stripJsonComments = (jsonString) => {
          // 移除单行注释 (// 开头的注释)
          let result = jsonString.replace(/\/\/.*$/gm, "");

          // 移除逗号后面紧跟着闭合括号或大括号的情况 (JSON不允许尾随逗号)
          result = result.replace(/,(\s*[}\]])/g, "$1");

          return result;
        };

        const contentWithoutComments = stripJsonComments(packageFile.content);
        console.log("处理后的JSON:", contentWithoutComments);

        try {
          const packageData = JSON.parse(contentWithoutComments);
          if (packageData.dependencies) {
            Object.assign(dependencies, packageData.dependencies || {});
            console.log("从package.json加载依赖:", dependencies);

            // 从CDN加载依赖
            try {
              await loadDependenciesFromCDN(dependencies, moduleCache);
            } catch (loadError) {
              console.error("从CDN加载依赖失败:", loadError);
              error.value = `从CDN加载依赖失败: ${loadError.message}`;
              dependenciesLoadFailed = true;
              loading.value = false;
              return;
            }
          }
        } catch (jsonError) {
          console.error("JSON解析错误:", jsonError);
          error.value = `package.json格式错误: ${jsonError.message}\n请确保JSON格式正确，并注意JSON中不支持注释，需要删除注释后才能正确解析`;
          loading.value = false;
          return;
        }
      }
    } catch (e) {
      console.error("解析package.json失败:", e);
      error.value = `解析package.json失败: ${e.message}`;
      loading.value = false;
      return;
    }

    if (dependenciesLoadFailed) return;

    console.log("使用的依赖:", dependencies);
    console.log("已加载的模块缓存:", Object.keys(moduleCache));

    const options = {
      moduleCache,
      getFile(path) {
        console.log("获取文件:", path);

        // 提取文件路径，去掉开头的斜杠
        const normalizedPath = path.startsWith("/") ? path.substring(1) : path;

        // 检查是否在虚拟文件系统中
        if (virtualFileSystem[path]) {
          return virtualFileSystem[path];
        }

        // 查找匹配的文件（忽略路径前缀）
        const matchingFile = files.value.find((f) =>
          normalizedPath.endsWith(f.name)
        );
        if (matchingFile) {
          return matchingFile.content;
        }

        // 处理样式预处理器模块和文件
        const stylePreprocessors = ["scss", "sass", "less", "stylus", "styl"];
        const hasPreprocessorExtension = stylePreprocessors.some((ext) =>
          path.endsWith(`.${ext}`)
        );

        // 直接处理样式预处理器模块名
        if (
          stylePreprocessors.includes(path) ||
          stylePreprocessors.includes(normalizedPath)
        ) {
          console.log(`样式预处理器模块请求: ${path}，提供增强模拟模块`);
          // 返回一个增强的预处理器模块模拟实现
          return `
            // 增强模拟${path}预处理器模块
            export default {
              // 基本处理方法，保持CSS内容不变
              render: (content) => content,
              compile: (content) => content,
              
              // 提供静态处理方法
              process: function(content, options) {
                return { css: content };
              },
              
              // 提供异步处理方法
              async processAsync(content, options) {
                return { css: content };
              },
              
              // 提供转换方法
              renderSync: function(options) {
                return {
                  css: options.data || options.content || '',
                  map: null,
                  stats: {}
                };
              },
              
              // 提供兼容API
              compileString: function(content, options) {
                return {
                  css: content,
                  dependencies: []
                };
              }
            };
          `;
        }

        if (hasPreprocessorExtension) {
          console.log(`样式预处理器文件请求: ${path}，转换为普通CSS`);
          // 返回一个能被处理的CSS内容
          return `/* 从 ${path} 转换而来的CSS */
          :root { --from-preprocessor: true; }`;
        }

        throw new Error(`未找到模块: ${path}`);
      },
      addStyle(textContent) {
        console.log("添加样式，长度:", textContent.length);
        const style = document.createElement("style");
        style.textContent = textContent;
        document.head.appendChild(style);
        return () => {
          document.head.removeChild(style);
        };
      },
      handleModule(type, source, path, options) {
        if (type === ".json") {
          return JSON.parse(source);
        }

        // 处理样式预处理器文件
        const styleTypes = {
          ".scss": true,
          ".sass": true,
          ".less": true,
          ".stylus": true,
          ".styl": true,
        };

        if (styleTypes[type]) {
          console.log(`在handleModule中处理样式预处理器文件: ${type}`);
          return source; // 直接返回源码作为CSS
        }
      },
      log(type, ...args) {
        console.log(`[vue3-sfc-loader][${type}]`, ...args);
      },
      compiledCache: new Map(),
    };

    console.log("创建异步组件");
    loadModule(moduleId, options)
      .then((component) => {
        console.log("组件加载成功:", component);
        if (!component) {
          throw new Error("组件加载结果为空");
        }
        previewComp.value = markRaw(component);
        error.value = "";
      })
      .catch((err) => {
        console.error("组件加载失败:", err);
        error.value = `组件加载失败: ${err.message || "未知错误"}`;
      })
      .finally(() => {
        loading.value = false;
        console.log("组件编译流程完成");
      });
  } catch (err) {
    console.error("组件编译过程出错:", err);
    error.value = `组件编译出错: ${err.message || "未知错误"}`;
    loading.value = false;
  }
};

// 从CDN加载依赖
const loadDependenciesFromCDN = async (dependencies, moduleCache) => {
  console.log("开始从CDN加载依赖...");

  // 转换依赖为加载任务数组
  const loadTasks = Object.entries(dependencies).map(([name, version]) => {
    return loadDependencyFromCDN(name, version, moduleCache);
  });

  // 并行加载所有依赖
  await Promise.all(loadTasks);
  console.log("所有依赖加载完成");
};

// 从CDN加载单个依赖
const loadDependencyFromCDN = async (name, version, moduleCache) => {
  // 清除版本号中的脱字符号(^)和波浪号(~)
  const cleanVersion = version.replace(/[\^~]/g, "");
  console.log(`加载依赖: ${name}@${cleanVersion}`);

  try {
    // 特殊依赖处理
    if (name === "vue" && moduleCache.vue) {
      console.log("Vue已预加载，跳过CDN加载");
      return;
    }

    if (name === "three" && moduleCache.three) {
      console.log("Three.js已预加载，跳过CDN加载");
      return;
    }

    // 检查是否为作用域包（以@开头）
    const isScopedPackage = name.startsWith("@");

    // 常见库的特殊CDN URL映射
    const specialCases = {
      vue: `https://unpkg.com/vue@${cleanVersion}/dist/vue.esm-browser.prod.js`,
      "vue-router": `https://unpkg.com/vue-router@${cleanVersion}/dist/vue-router.esm-browser.js`,
      vuex: `https://unpkg.com/vuex@${cleanVersion}/dist/vuex.esm-browser.js`,
      "element-plus": `https://unpkg.com/element-plus@${cleanVersion}/dist/index.full.mjs`,
      "@element-plus/icons-vue": `https://unpkg.com/@element-plus/icons-vue@${cleanVersion}/dist/index.mjs`,
      axios: `https://unpkg.com/axios@${cleanVersion}/dist/axios.min.js`,
      lodash: `https://unpkg.com/lodash-es@${cleanVersion}/lodash.js`,
      moment: `https://unpkg.com/moment@${cleanVersion}/dist/moment.js`,
      dayjs: `https://unpkg.com/dayjs@${cleanVersion}/esm/index.js`,
      three: `https://unpkg.com/three@${cleanVersion}/build/three.module.js`,
    };

    // 需要额外加载CSS的库
    const cssLibraries = {
      "element-plus": `https://unpkg.com/element-plus@${cleanVersion}/dist/index.css`,
      "ant-design-vue": `https://unpkg.com/ant-design-vue@${cleanVersion}/dist/antd.min.css`,
      vant: `https://unpkg.com/vant@${cleanVersion}/lib/index.css`,
      "bootstrap-vue": `https://unpkg.com/bootstrap-vue@${cleanVersion}/dist/bootstrap-vue.min.css`,
      vuetify: `https://unpkg.com/vuetify@${cleanVersion}/dist/vuetify.min.css`,
    };

    // 构建CDN URL
    let cdnUrl;
    if (specialCases[name]) {
      cdnUrl = specialCases[name];
    } else if (isScopedPackage) {
      // 作用域包的特殊处理
      // 提取作用域名称和包名
      const [scope, packageName] = name.slice(1).split("/");

      // 为作用域包构建更准确的URL
      cdnUrl = `https://unpkg.com/${name}@${cleanVersion}/dist/index.mjs`;

      // 针对作用域包的备选URL数组
      const scopedFallbackUrls = [
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.js`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.esm.js`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.esm.mjs`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.min.js`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.full.js`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.full.mjs`,
        `https://unpkg.com/${name}@${cleanVersion}`,
        `https://cdn.jsdelivr.net/npm/${name}@${cleanVersion}/dist/index.mjs`,
        `https://cdn.jsdelivr.net/npm/${name}@${cleanVersion}/dist/index.js`,
        `https://cdn.jsdelivr.net/npm/${name}@${cleanVersion}`,
        `https://esm.sh/${name}@${cleanVersion}`,
      ];

      // 尝试预检查URL是否存在
      try {
        const response = await fetch(cdnUrl, { method: "HEAD" });
        if (!response.ok) {
          // 如果主URL不存在，尝试备用URL
          for (const url of scopedFallbackUrls) {
            try {
              const fallbackResponse = await fetch(url, { method: "HEAD" });
              if (fallbackResponse.ok) {
                cdnUrl = url;
                console.log(`找到有效的作用域包URL: ${url}`);
                break;
              }
            } catch (e) {
              continue;
            }
          }
        }
      } catch (e) {
        console.warn(`预检查作用域包CDN URL失败: ${e.message}，尝试直接加载`);
      }
    } else {
      // 默认使用unpkg的ESM模块
      cdnUrl = `https://unpkg.com/${name}@${cleanVersion}/dist/${name}.esm.js`;

      // 备用URL（如果默认不存在）
      const fallbackUrls = [
        `https://unpkg.com/${name}@${cleanVersion}`,
        `https://unpkg.com/${name}@${cleanVersion}/index.js`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.js`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.esm.js`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/index.mjs`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/${name}.js`,
        `https://unpkg.com/${name}@${cleanVersion}/dist/${name}.min.js`,
        `https://cdn.jsdelivr.net/npm/${name}@${cleanVersion}/dist/${name}.esm.js`,
        `https://cdn.jsdelivr.net/npm/${name}@${cleanVersion}/dist/index.js`,
        `https://cdn.jsdelivr.net/npm/${name}@${cleanVersion}`,
        `https://esm.sh/${name}@${cleanVersion}`,
      ];

      // 尝试预检查URL是否存在
      try {
        const response = await fetch(cdnUrl, { method: "HEAD" });
        if (!response.ok) {
          // 如果主URL不存在，尝试备用URL
          for (const url of fallbackUrls) {
            try {
              const fallbackResponse = await fetch(url, { method: "HEAD" });
              if (fallbackResponse.ok) {
                cdnUrl = url;
                break;
              }
            } catch (e) {
              continue;
            }
          }
        }
      } catch (e) {
        console.warn(`预检查CDN URL失败: ${e.message}，尝试直接加载`);
      }
    }

    console.log(`尝试从 ${cdnUrl} 加载 ${name}`);

    // 针对Element Plus图标库的特殊处理
    if (name === "@element-plus/icons-vue") {
      try {
        console.log("正在使用特殊方法加载Element Plus图标库...");

        // 尝试多个可能的CDN URL
        const iconsFallbacks = [
          `https://unpkg.com/@element-plus/icons-vue@${cleanVersion}/dist/index.mjs`,
          `https://unpkg.com/@element-plus/icons-vue@${cleanVersion}/dist/index.js`,
          `https://cdn.jsdelivr.net/npm/@element-plus/icons-vue@${cleanVersion}/dist/index.mjs`,
          `https://cdn.jsdelivr.net/npm/@element-plus/icons-vue@${cleanVersion}`,
          `https://esm.sh/@element-plus/icons-vue@${cleanVersion}`,
        ];

        let iconsModule = null;
        let loadError = null;

        // 尝试所有可能的URL
        for (const url of iconsFallbacks) {
          try {
            console.log(`尝试从 ${url} 加载 Element Plus 图标库`);
            iconsModule = await import(/* @vite-ignore */ url);
            if (iconsModule) {
              console.log(`成功从 ${url} 加载 Element Plus 图标库`);
              break;
            }
          } catch (err) {
            console.warn(`从 ${url} 加载图标库失败，尝试下一个URL`);
            loadError = err;
          }
        }

        if (iconsModule) {
          // 检查各种可能的导出格式
          if (iconsModule.default) {
            moduleCache[name] = iconsModule.default;
          } else {
            moduleCache[name] = iconsModule;
          }

          console.log("Element Plus图标库加载成功");
          return;
        } else if (loadError) {
          throw loadError;
        }
      } catch (iconsError) {
        console.error("Element Plus图标库加载失败:", iconsError);
        throw new Error(`无法加载Element Plus图标库: ${iconsError.message}`);
      }
    }

    // 针对Element Plus的特殊处理
    if (name === "element-plus") {
      try {
        // 先加载CSS
        if (cssLibraries[name]) {
          await loadCSSFromCDN(cssLibraries[name]);
          console.log(`已加载 ${name} 的样式文件`);
        }

        // 尝试使用更多备选URL
        const elementPlusFallbacks = [
          `https://unpkg.com/element-plus@${cleanVersion}/dist/index.full.mjs`,
          `https://unpkg.com/element-plus@${cleanVersion}/dist/index.full.min.js`,
          `https://cdn.jsdelivr.net/npm/element-plus@${cleanVersion}/dist/index.full.min.js`,
          `https://cdn.jsdelivr.net/npm/element-plus@${cleanVersion}`,
          `https://esm.sh/element-plus@${cleanVersion}`,
        ];

        let elementPlusModule = null;
        let loadError = null;

        // 尝试所有可能的URL直到成功
        for (const url of elementPlusFallbacks) {
          try {
            console.log(`尝试从 ${url} 加载 Element Plus`);
            elementPlusModule = await import(/* @vite-ignore */ url);
            if (elementPlusModule) {
              console.log(`成功从 ${url} 加载 Element Plus`);
              break;
            }
          } catch (err) {
            console.warn(`从 ${url} 加载失败，尝试下一个URL`);
            loadError = err;
          }
        }

        if (elementPlusModule) {
          // 检查各种可能的导出格式
          if (elementPlusModule.default) {
            moduleCache[name] = elementPlusModule.default;
          } else {
            moduleCache[name] = elementPlusModule;
          }

          // 如果加载成功但未能获取模块，创建一个最小化的模拟模块
          if (!moduleCache[name]) {
            console.warn("Element Plus模块结构异常，创建模拟模块");
            moduleCache[name] = elementPlusModule;
          }

          return;
        } else if (loadError) {
          throw loadError;
        }
      } catch (elementError) {
        console.error(
          "Element Plus加载失败，尝试通过script标签加载:",
          elementError
        );

        // 尝试通过script标签加载备选格式
        try {
          const scriptUrl = `https://unpkg.com/element-plus@${cleanVersion}/dist/index.full.min.js`;
          await loadScriptTag(scriptUrl, name);

          // 检查全局ElementPlus对象
          if (window.ElementPlus) {
            console.log("成功从window.ElementPlus获取Element Plus");
            moduleCache[name] = window.ElementPlus;
            return;
          } else {
            console.error("无法从window.ElementPlus获取Element Plus");
            throw new Error("无法从script加载获取Element Plus");
          }
        } catch (scriptError) {
          console.error("通过script标签加载Element Plus失败:", scriptError);
          throw scriptError;
        }
      }
    }

    // 为其他有CSS的库加载样式
    if (cssLibraries[name] && name !== "element-plus") {
      await loadCSSFromCDN(cssLibraries[name]);
      console.log(`已加载 ${name} 的样式文件`);
    }

    // 尝试通过动态import加载模块（常规流程）
    try {
      const module = await import(/* @vite-ignore */ cdnUrl);
      console.log(`成功加载模块: ${name}`);

      // 将加载的模块添加到缓存
      if (module.default) {
        moduleCache[name] = module.default;
      } else {
        moduleCache[name] = module;
      }
    } catch (e) {
      console.error(`无法从CDN加载 ${name}: ${e.message}`);

      // 如果是模块解析错误，尝试通过script标签加载
      if (e.message.includes("module") || e.message.includes("import")) {
        console.log(`尝试通过script标签加载 ${name}`);

        // 构建适合script标签的URL
        let scriptUrl = cdnUrl;
        // 如果URL以.mjs或.esm结尾，尝试替换为.js或.min.js版本
        if (scriptUrl.endsWith(".mjs") || scriptUrl.endsWith(".esm.js")) {
          scriptUrl = scriptUrl
            .replace(".mjs", ".min.js")
            .replace(".esm.js", ".min.js");
          if (
            scriptUrl.includes("unpkg.com") &&
            !scriptUrl.includes("/dist/")
          ) {
            // 尝试调整到常见的dist目录结构
            const parts = scriptUrl.split("@");
            if (parts.length > 1) {
              const [baseUrl, versionAndPath] = parts;
              const versionParts = versionAndPath.split("/");
              const version = versionParts[0];
              scriptUrl = `${baseUrl}@${version}/dist/index.min.js`;
            }
          }
        }

        await loadScriptTag(scriptUrl, name);

        // 处理不同库的全局对象命名
        const globalNames = {
          "element-plus": "ElementPlus",
          "@element-plus/icons-vue": "ElementPlusIconsVue",
          "vue-router": "VueRouter",
          vuex: "Vuex",
          axios: "axios",
          lodash: "_",
          moment: "moment",
          dayjs: "dayjs",
          three: "THREE",
        };

        // 尝试从window全局对象获取
        const globalName = globalNames[name] || name.replace(/[-/@]/g, "");
        if (window[globalName]) {
          moduleCache[name] = window[globalName];
          console.log(`从window.${globalName}获取 ${name} 成功`);
        } else if (window[name]) {
          moduleCache[name] = window[name];
          console.log(`从window.${name}获取 ${name} 成功`);
        } else if (isScopedPackage) {
          // 作用域包可能会有特殊的全局变量名
          const simpleName = name.split("/").pop();
          const camelCaseName = simpleName.replace(/-([a-z])/g, (g) =>
            g[1].toUpperCase()
          );
          const pascalCaseName =
            camelCaseName.charAt(0).toUpperCase() + camelCaseName.slice(1);

          // 尝试各种可能的全局变量名形式
          const possibleNames = [
            // 直接使用最后一部分
            simpleName,
            // 驼峰形式
            camelCaseName,
            // 帕斯卡形式
            pascalCaseName,
            // 作用域+包名连接形式(移除@和/)
            name.replace(/[@/]/g, ""),
          ];

          let found = false;
          for (const possibleName of possibleNames) {
            if (window[possibleName]) {
              moduleCache[name] = window[possibleName];
              console.log(`从window.${possibleName}获取 ${name} 成功`);
              found = true;
              break;
            }
          }

          if (!found) {
            console.error(
              `无法找到作用域包 ${name} 的全局变量，尝试过:`,
              possibleNames
            );
            console.log(
              "可用的全局变量:",
              Object.keys(window)
                .filter(
                  (key) =>
                    typeof window[key] === "object" ||
                    typeof window[key] === "function"
                )
                .slice(0, 30)
            );
            throw new Error(`无法从window全局对象获取作用域包 ${name}`);
          }
        } else {
          console.error(`无法从window全局对象获取 ${name}`);
          throw new Error(
            `无法从window全局对象获取 ${name}，尝试过 window.${globalName} 和 window.${name}`
          );
        }
      } else {
        throw e;
      }
    }
  } catch (error) {
    console.error(`加载依赖 ${name}@${cleanVersion} 失败:`, error);
    throw new Error(`无法加载依赖 ${name}@${cleanVersion}: ${error.message}`);
  }
};

// 通过script标签加载依赖
const loadScriptTag = (url, name) => {
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");
    script.src = url;
    script.async = true;

    script.onload = () => {
      console.log(`Script加载成功: ${url}`);
      resolve();
    };

    script.onerror = () => {
      console.error(`Script加载失败: ${url}`);
      reject(new Error(`加载脚本失败: ${url}`));
    };

    document.head.appendChild(script);
  });
};

// 加载CSS文件
const loadCSSFromCDN = (url) => {
  return new Promise((resolve, reject) => {
    const link = document.createElement("link");
    link.rel = "stylesheet";
    link.href = url;

    link.onload = () => {
      console.log(`CSS加载成功: ${url}`);
      resolve();
    };

    link.onerror = () => {
      console.error(`CSS加载失败: ${url}`);
      reject(new Error(`加载CSS失败: ${url}`));
    };

    document.head.appendChild(link);
  });
};

// 页面加载时编译默认组件
onMounted(() => {
  compileComponent();
});

// 监听文件变化
watch(
  files,
  () => {
    // 当文件内容变化时，延迟刷新预览（可选）
  },
  { deep: true }
);
</script>

<style scoped>
.editor-container {
  display: flex;
  flex-direction: row;
  height: 100vh;
  width: 100%;
  background-color: #1e1e2f;
  color: #f0f0f0;
}

.code-panel {
  width: 50%;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-right: 1px solid #333;
}

:deep(.cm-editor) {
  height: calc(100vh - 130px);
}

/* 文件页签样式 */
.file-tabs {
  display: flex;
  overflow-x: auto;
  background-color: #252538;
  border-bottom: 1px solid #333;
  height: 65px;

  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-direction: row;
}

.file-tab {
  display: flex;
  align-items: center;
  padding: 0 12px;
  height: 40px;
  background-color: #1e1e2f;
  border-right: 1px solid #333;
  cursor: pointer;
  font-size: 0.85rem;
  white-space: nowrap;
}

.file-tab.active {
  background-color: #2c2c44;
  border-bottom: 2px solid #4c84ff;
}

.file-icon {
  margin-right: 6px;
  font-size: 10px;
  font-weight: bold;
  padding: 2px 4px;
  border-radius: 3px;
  background-color: #333;
}

.icon-vue {
  background-color: #42b883;
  color: #fff;
}

.icon-js {
  background-color: #f7df1e;
  color: #000;
}

.icon-ts {
  background-color: #3178c6;
  color: #fff;
}

.icon-json {
  background-color: #8d8d8d;
  color: #fff;
}

.icon-html {
  background-color: #e44d26;
  color: #fff;
}

.icon-css {
  background-color: #264de4;
  color: #fff;
}

.icon-file {
  background-color: #607d8b;
  color: #fff;
}

.close-tab {
  margin-left: 8px;
  opacity: 0.5;
}

.close-tab:hover {
  opacity: 1;
  color: #ff6b6b;
}

.add-file-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  background-color: #252538;
  cursor: pointer;
  font-size: 18px;
  font-weight: bold;
}

.add-file-tab:hover {
  background-color: #2c2c44;
}

/* 新建文件弹窗 */
.new-file-modal {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal-content {
  background-color: #252538;
  border-radius: 6px;
  padding: 20px;
  width: 300px;
}

.modal-content h3 {
  margin-top: 0;
  margin-bottom: 16px;
}

.modal-content input {
  width: 100%;
  padding: 8px;
  margin-bottom: 16px;
  background-color: #1e1e2f;
  border: 1px solid #333;
  color: #f0f0f0;
  border-radius: 4px;
}

.modal-buttons {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

.modal-buttons button {
  padding: 6px 12px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.modal-buttons button:first-child {
  background-color: #4c84ff;
  color: white;
}

.modal-buttons button:last-child {
  background-color: #333;
  color: #f0f0f0;
}

.dependency-hint {
  background-color: #252538;
  border-bottom: 1px solid #333;
  padding: 8px;
}

.hint-message {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.hint-tips {
  margin-top: 8px;
  font-size: 0.8rem;
  color: #aaa;
  background-color: #1e1e2f;
  padding: 8px;
  border-radius: 4px;
}

.hint-tips p {
  margin: 0 0 4px 0;
  color: #bbb;
}

.hint-tips ul {
  margin: 0;
  padding-left: 20px;
}

.hint-tips li {
  margin-bottom: 2px;
}

.refresh-btn {
  padding: 0.25rem 0.75rem;
  background-color: #4c84ff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.875rem;
  transition: background-color 0.2s;
}

.refresh-btn:hover {
  background-color: #3a70e3;
}

.preview-container {
  width: 50%;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #fff;
  color: #333;
}

.preview-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.5rem 1rem;
  background-color: #f5f5f5;
  border-bottom: 1px solid #ddd;
  height: 40px;
}

.preview-content {
  flex: 1;
  position: relative;
  overflow: auto;
  padding: 1rem;
}

.component-container {
  min-height: 100%;
  width: 100%;
}

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: rgba(255, 255, 255, 0.8);
  z-index: 10;
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 10px;
}

.loading-spinner.small {
  width: 16px;
  height: 16px;
  border: 2px solid #f3f3f3;
  border-top: 2px solid #3498db;
  margin-right: 8px;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.error {
  color: #f56c6c;
  padding: 10px;
  background-color: #fef0f0;
  border-radius: 4px;
  margin: 10px 0;
}
</style>
